home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / CDTools / Viewers / Flick / src / flick.c < prev    next >
C/C++ Source or Header  |  1995-05-21  |  64KB  |  2,094 lines

  1. /*****************************************************************************
  2.  
  3.         Flick FLI-format Animation Viewer v1.5          21 May 1995
  4.         --------------------------------------
  5.  
  6.  
  7. This program plays FLI/FLC-format bitmapped animation files on any ECS,
  8. AGA or EGS Amiga running OS2.04 or higher.  FLI/FLC-format files are
  9. produced by Autodesk Animator and Autodesk 3D Studio on a PC, as well
  10. as by other programs.
  11.  
  12. The files in this archive may be distributed anywhere provided they are
  13. unmodified and are not sold for profit.
  14.  
  15. Ownership and copyright of all files remains with the author:
  16.  
  17.     Peter McGavin, 86 Totara Crescent, Lower Hutt, New Zealand.
  18.     e-mail: peterm@maths.grace.cri.nz
  19.  
  20. *****************************************************************************/
  21.  
  22. #include "includes.h"
  23.  
  24. const char version[] = "$VER: Flick 1.5 " __AMIGADATE__ ;
  25.  
  26. long __oslibversion = 37;    /* we require at least OS2.0 */
  27.  
  28. char __stdiowin[] = "CON:20/50/500/130/Flick";
  29. char __stdiov37[] = "/AUTO/CLOSE";
  30.  
  31. #define FLI_256_COLOR  4
  32. #define FLI_SS2        7
  33. #define FLI_COLOR     11
  34. #define FLI_LC        12
  35. #define FLI_BLACK     13
  36. #define FLI_BRUN      15
  37. #define FLI_COPY      16
  38. #define FLI_PSTAMP    18
  39.  
  40. struct header {
  41.   ULONG size;
  42.   UWORD magic;
  43.   UWORD frames;
  44.   UWORD width;
  45.   UWORD height;
  46.   UWORD depth;
  47.   UWORD flags;
  48.   ULONG speed;
  49.   UWORD reserved1;
  50.   ULONG created;
  51.   ULONG creator;
  52.   ULONG updated;
  53.   ULONG updater;
  54.   UWORD aspectx;
  55.   UWORD aspecty;
  56.   UBYTE reserved2[38];
  57.   ULONG oframe1;
  58.   ULONG oframe2;
  59.   UBYTE reserved3[40];
  60. };
  61.  
  62. struct frameheader {
  63.   ULONG size;
  64.   UWORD magic;
  65.   UWORD chunks;
  66.   UBYTE expand[8];
  67. };
  68.  
  69. struct chunkheader {
  70.   ULONG size;
  71.   UWORD type;
  72. };
  73.  
  74. struct options {
  75.   BOOL ram;
  76.   enum mode_type mode;
  77.   BOOL once;
  78.   BOOL rom;
  79.   BOOL dbuf;
  80.   BOOL warp;
  81.   BOOL akiko;
  82. };
  83.  
  84. struct Library *EGSBase = NULL;
  85. struct Library *EGSGfxBase = NULL;
  86. struct Library *EGSBlitBase = NULL;
  87. struct Library *EGSIntuiBase = NULL;
  88.  
  89. PLANEPTR raster[2] = {NULL, NULL};    /* 8 contiguous bitplanes */
  90. struct BitMap screen_bm[2];    /* The displayed bitmap */
  91. struct RastPort rp[2];
  92.  
  93. UWORD __chip emptypointer[] = {
  94.     0x0000, 0x0000,        /* reserved, must be NULL */
  95.     0x0000, 0x0000,     /* 1 row of image data */
  96.     0x0000, 0x0000};    /* reserved, must be NULL */
  97.  
  98. struct ExtNewScreen ns = {
  99.         0,0,0,0,0,
  100.         2,1,
  101.         0 /* HIRES | LACE */,
  102.         CUSTOMSCREEN | CUSTOMBITMAP,
  103.         NULL,
  104.         NULL,
  105.         NULL,
  106.         &screen_bm[0]
  107. };
  108.  
  109. struct NewWindow nw = {
  110.         0,0,            /* Starting corner */
  111.         0,0,            /* Width, height */
  112.         2,1,            /* detail, block pens */
  113.         IDCMP_VANILLAKEY | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS, /* IDCMP flags */
  114.         WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_RMBTRAP,    /* Window flags */
  115.         NULL,            /* Pointer to first gadget */
  116.         NULL,            /* Pointer to checkmark */
  117.         NULL,            /* title */
  118.         NULL,            /* screen pointer */
  119.         NULL,            /* bitmap pointer */
  120.         0,0,0,0,        /* window not sized */
  121.         CUSTOMSCREEN        /* type of screen */
  122.         };
  123.  
  124. struct Screen *s = NULL;
  125. struct Window *w = NULL;
  126.  
  127. static struct EI_NewScreen ei_ns = {
  128.     NULL,                     /* screenmode name is put here later... */
  129.     8, 0, &version[6],        /* depth, pad, title */
  130.     NULL,                     /* CLUPtr */
  131.     { 3, 1, 0, 2, 1, 3, 1 },  /* WinColors */
  132.     0,                        /* backPen */
  133.     NULL,                     /* backPattern */
  134.     NULL,                     /* Maus */
  135.     NULL                      /* TextAttr */
  136. };
  137.  
  138. static struct EI_NewWindow ei_nw =
  139. {
  140.     0, 0, 320, 200,         /* LeftEdge, TopEdge, Width, Height */
  141.     0, 0, 320, 200,        /* MinWidth,MinHeight, MaxWidth, MaxHeight */
  142.     NULL,            /* Screen - might be set to some screen later */
  143.     EI_WINDOWCLOSE | EI_WINDOWBACK | EI_WINDOWDRAG,    /* SysGadgets */
  144.     NULL,            /* FirstGadgets */
  145.     &version[6],        /* Title */
  146.     EI_SMART_REFRESH | EI_GIMMEZEROZERO | EI_WINDOWACTIVE | EI_RMBTRAP,    /* Flags */
  147.     EI_iCLOSEWINDOW | EI_iVANILLAKEY | EI_iRAWKEY | EI_iMOUSEBUTTONS |
  148.         EI_iACTIVEWINDOW | EI_iINACTIVEWINDOW,    /*EI_IDCMPFlags */
  149.     NULL,            /*Port */
  150.     {0,0,0,0,0,0,0},    /* Colors */
  151.     NULL,            /* Menu */
  152.     NULL            /* Render */
  153. };
  154.  
  155. EI_ScreenPtr ei_s = NULL;
  156. EI_WindowPtr ei_w = NULL;
  157. E_EBitMapPtr e_bm = NULL;
  158. E_CLU *e_oldscreencolours = NULL;
  159. E_CLU *e_screencolours = NULL;
  160. EG_RastPortPtr eg_rp;
  161.  
  162. UWORD screen_width;
  163. UWORD screen_depth;
  164. UWORD screen_width32;        /* screen_width/32 */
  165.  
  166. struct ScreenBuffer *sb[2] = {NULL, NULL};
  167. struct MsgPort *safeport = NULL;
  168. struct MsgPort *dispport = NULL;
  169. BOOL safe = TRUE;
  170. BOOL disp = TRUE;
  171.  
  172. struct RastPort temprp;        /* for WritePixelArray8() */
  173. struct BitMap *tmp_bm = NULL;    /* for WritePixelArray8(), Height=1, Depth=? */
  174. PLANEPTR tmpras = NULL;        /* for WritePixelArray8() */
  175.  
  176. UBYTE *chunky = NULL;        /* screen_width*h.height chunky pixels */
  177.  
  178. struct header h;
  179.  
  180. struct Library *TimerBase = NULL;
  181. struct MsgPort *timermp = NULL;
  182. struct timerequest *timerio = NULL;
  183. ULONG timerclosed = TRUE;
  184. struct EClockVal *time = NULL;
  185. struct EClockVal *time0 = NULL;
  186. struct EClockVal *time1 = NULL;
  187. double micros_per_eclock;    /* Length of EClock tick in microseconds */
  188.  
  189. struct Task *thistask = NULL;
  190. BOOL v39 = FALSE;
  191. BOOL v40 = FALSE;
  192. ULONG cpu_type;  /* 68000, 68010, 68020, 68030, 68040, 68060 */
  193.  
  194. char programname[20];
  195. BPTR olddir = NULL;
  196. struct RDArgs *rdargs = NULL;
  197.  
  198. struct Library *AslBase = NULL;
  199. struct FileRequester *fr = NULL;
  200. struct ScreenModeRequester *smr = NULL;
  201.  
  202.  
  203. /****************************************************************************/
  204.  
  205. void swapw (UWORD *w)
  206. /* Swap the bytes around in a word which may be on an odd byte-boundary */
  207. {
  208.   UBYTE t;
  209.  
  210.   t = ((UBYTE *)w)[0];
  211.   ((UBYTE *)w)[0] = ((UBYTE *)w)[1];
  212.   ((UBYTE *)w)[1] = t;
  213. }
  214.  
  215. void swapl (ULONG *l)
  216. /* Swap the bytes around in a longword which may be on an odd byte-boundary */
  217. {
  218.   UBYTE t;
  219.  
  220.   t = ((UBYTE *)l)[0];
  221.   ((UBYTE *)l)[0] = ((UBYTE *)l)[3];
  222.   ((UBYTE *)l)[3] = t;
  223.   t = ((UBYTE *)l)[1];
  224.   ((UBYTE *)l)[1] = ((UBYTE *)l)[2];
  225.   ((UBYTE *)l)[2] = t;
  226. }
  227.  
  228. UWORD extractw (UWORD *w)
  229. /* Get a word which may be on an odd byte-boundary */
  230. {
  231.   UBYTE t[2];
  232.  
  233.   t[0] = ((UBYTE *)w)[0];
  234.   t[1] = ((UBYTE *)w)[1];
  235.   return *(UWORD *)t;
  236. }
  237.  
  238. ULONG extractl (ULONG *l)
  239. /* Get a longword which may be on an odd byte-boundary */
  240. {
  241.   UBYTE t[4];
  242.  
  243.   t[0] = ((UBYTE *)l)[0];
  244.   t[1] = ((UBYTE *)l)[1];
  245.   t[2] = ((UBYTE *)l)[2];
  246.   t[3] = ((UBYTE *)l)[3];
  247.   return *(ULONG *)t;
  248. }
  249.  
  250. /****************************************************************************/
  251.  
  252. void close_screen (void)
  253. {
  254.   int which;
  255.  
  256.   if (chunky != NULL) {
  257.     if (e_bm == NULL || chunky != e_bm->Plane)
  258.       free (chunky);
  259.     chunky = NULL;
  260.   };
  261.   if (e_bm != NULL) {
  262.     e_bm->Lock--;
  263.     E_DisposeBitMap(e_bm);
  264.     e_bm = NULL;
  265.   }
  266.   if (e_oldscreencolours != NULL) {
  267.     E_SetRGB8CM (ei_w->WScreen->EScreen, e_oldscreencolours, 0, 256);
  268.     free (e_oldscreencolours);
  269.     e_oldscreencolours = NULL;
  270.   }
  271.   if (e_screencolours != NULL) {
  272.     free (e_screencolours);
  273.     e_screencolours = NULL;
  274.   }
  275.   if (ei_w != NULL) {
  276.     EI_CloseWindow (ei_w);
  277.     ei_w = NULL;
  278.   }
  279.   if (ei_s != NULL) {
  280.     EI_CloseScreen (ei_s);
  281.     ei_s = NULL;
  282.   }
  283.   if (w != NULL) {
  284.     ClearPointer (w);
  285.     CloseWindow (w);
  286.     w = NULL;
  287.   }
  288.   if (sb[1] != NULL) {
  289.     FreeScreenBuffer (s, sb[1]);
  290.     sb[1] = NULL;
  291.   }
  292.   if (sb[0] != NULL) {
  293.     FreeScreenBuffer (s, sb[0]);
  294.     sb[0] = NULL;
  295.   }
  296.   if (s != NULL) {
  297.     CloseScreen (s);
  298.     s = NULL;
  299.   }
  300.   if (dispport != NULL) {
  301.     DeletePort (dispport);
  302.     dispport = NULL;
  303.   }
  304.   if (safeport != NULL) {
  305.     DeletePort (safeport);
  306.     safeport = NULL;
  307.   }
  308.   for (which = 0; which < 2; which++) {
  309.     if (raster[which] != NULL) {
  310.       FreeRaster (raster[which], screen_width, screen_depth * h.height);
  311.       raster[which] = NULL;
  312.     }
  313.   }
  314. }
  315.  
  316. /****************************************************************************/
  317.  
  318. void _STDcleanup (void)
  319. /* This get called automatically by SAS/C 6.3 on any sort of exit condition */
  320. {
  321.   if (!safe) {
  322.     Wait (1 << safeport->mp_SigBit | SIGBREAKF_CTRL_C);
  323.     while (GetMsg (safeport) != NULL) /* clear message queue */
  324.       /* nothing */ ;
  325.     safe = TRUE;
  326.   }
  327.   if (!disp) {
  328.     Wait (1 << dispport->mp_SigBit | SIGBREAKF_CTRL_C);
  329.     while (GetMsg (dispport) != NULL) /* clear message queue */
  330.       /* nothing */ ;
  331.     disp = TRUE;
  332.   }
  333.   close_screen ();
  334.   if (tmp_bm != NULL) {
  335.     if (v39)
  336.       FreeBitMap (tmp_bm);
  337.     else
  338.       FreeMem (tmp_bm, sizeof(struct BitMap));
  339.     tmp_bm = NULL;
  340.   }
  341.   if (tmpras != NULL) {
  342.     FreeRaster (tmpras, screen_width, screen_depth);
  343.     tmpras = NULL;
  344.   }
  345.   if (time1 != NULL) {
  346.     FreeMem (time1, sizeof(struct EClockVal));
  347.     time1 = NULL;
  348.   }
  349.   if (time0 != NULL) {
  350.     FreeMem (time0, sizeof(struct EClockVal));
  351.     time0 = NULL;
  352.   }
  353.   if (time != NULL) {
  354.     FreeMem (time, sizeof(struct EClockVal));
  355.     time = NULL;
  356.   }
  357.   if (olddir != NULL) {
  358.     CurrentDir (olddir);
  359.     olddir = NULL;
  360.   }
  361.   if (rdargs != NULL) {
  362.     FreeArgs (rdargs);
  363.     rdargs = NULL;
  364.   }
  365.   if (!timerclosed) {
  366.     CloseDevice ((struct IORequest *)timerio);
  367.     timerclosed = TRUE;
  368.     TimerBase = NULL;
  369.   }
  370.   if (timerio != NULL) {
  371.     DeleteExtIO ((struct IORequest *)timerio);
  372.     timerio = NULL;
  373.   }
  374.   if (timermp != NULL) {
  375.     DeletePort (timermp);
  376.     timermp = NULL;
  377.   }
  378.   if (EGSIntuiBase != NULL) {
  379.     CloseLibrary (EGSIntuiBase);
  380.     EGSIntuiBase = NULL;
  381.   }
  382.   if (EGSBlitBase != NULL) {
  383.     CloseLibrary (EGSBlitBase);
  384.     EGSBlitBase = NULL;
  385.   }
  386.   if (EGSGfxBase != NULL) {
  387.     CloseLibrary (EGSGfxBase);
  388.     EGSGfxBase = NULL;
  389.   }
  390.   if (EGSBase != NULL) {
  391.     CloseLibrary (EGSBase);
  392.     EGSBase = NULL;
  393.   }
  394.   if (smr != NULL) {
  395.     FreeAslRequest (smr);
  396.     smr = NULL;
  397.   }
  398.   if (fr != NULL) {
  399.     FreeAslRequest (fr);
  400.     fr = NULL;
  401.   }
  402.   if (AslBase != NULL) {
  403.     CloseLibrary (AslBase);
  404.     AslBase = NULL;
  405.   }
  406.   /* standard libraries are auto-closed here by SAS/C */
  407. }
  408.  
  409. /****************************************************************************/
  410.  
  411. static char bodystring[64];
  412.  
  413. static struct TextAttr topaz80 = {
  414.   "topaz.font", 8, 0, 0
  415. };
  416.  
  417. static struct IntuiText bodytext[] = {
  418.   {0, 1, JAM2, 10, 8, &topaz80, programname, &bodytext[1]},
  419.   {0, 1, JAM2, 10, 20, &topaz80, bodystring, NULL},
  420. };
  421.  
  422. static struct IntuiText negtext = {0, 1, JAM2, 6, 3, &topaz80, "Ok", NULL};
  423.  
  424. void die (char *msg, ...)
  425. /* Exit program with message, return code 10 */
  426. {
  427.   va_list arglist;
  428.  
  429.   va_start (arglist, msg);
  430.   vsprintf (bodystring, msg, arglist);
  431.   va_end (arglist);
  432.   AutoRequest (w, &bodytext[0], NULL, &negtext, 0, 0, 320, 60);
  433.   exit (10);
  434.   /* SAS/C executes _STDcleanup() automatically on exit */
  435. }
  436.  
  437. /****************************************************************************/
  438.  
  439. void *malloc_check (size_t size)
  440. {
  441.   void *p;
  442.  
  443.   if ((p = malloc (size)) == NULL)
  444.     die ("%s: Out of memory trying to allocate %ld bytes!", programname,
  445.          size);
  446.   return (p);
  447. }
  448.  
  449. /****************************************************************************/
  450.  
  451. void c2p_rom (UBYTE *chunky,
  452.               UBYTE *copy_of_chunky,
  453.               struct RastPort *rp,
  454.               struct RastPort *temprp,
  455.               UBYTE *dirty_list)
  456. {
  457.   ULONG h32, *p1, *p2;
  458.   UWORD x, y0, y1, w32, i;
  459.   UBYTE *p;
  460.  
  461.   w32 = screen_width >> 5;
  462.   h32 = w32 * (h.height - 1);
  463.   for (x = 0; x < screen_width; x += 32) {
  464.     p = dirty_list;
  465.     y0 = 0;
  466.     while (y0++ < h.height && !*p)
  467.       p += w32;
  468.     if (y0 < h.height) {
  469.       y0--;
  470.       p = dirty_list + h32;
  471.       y1 = h.height - 1;
  472.       while (!*p) {
  473.         p -= w32;
  474.         y1--;
  475.       }
  476.       p2 = (ULONG *)copy_of_chunky;
  477.       p1 = (ULONG *)(&chunky[y0 * screen_width + x]);
  478.       for (i = y1 - y0 + 1; i > 0; i--) {
  479.         *p2++ = *p1++;
  480.         *p2++ = *p1++;
  481.         *p2++ = *p1++;
  482.         *p2++ = *p1++;
  483.         *p2++ = *p1++;
  484.         *p2++ = *p1++;
  485.         *p2++ = *p1++;
  486.         *p2++ = *p1;
  487.         p1 += (screen_width >> 2) - 7;
  488.       }
  489.       WritePixelArray8 (rp, x, y0, x + 31, y1, copy_of_chunky, temprp);
  490.     }
  491.     dirty_list++;
  492.   }
  493. }
  494.  
  495. /****************************************************************************/
  496.  
  497. void c2p_egs (E_EBitMapPtr e_bm,
  498.               EG_RastPortPtr eg_rp,
  499.               UBYTE *dirty_list,
  500.               ULONG plsiz)
  501. {
  502.   ULONG h32;
  503.   UWORD x, y0, y1, w32;
  504.   UBYTE *p;
  505.  
  506.   w32 = e_bm->Width >> 5;
  507.   h32 = w32 * (e_bm->Height - 1);
  508.   for (x = 0; x < e_bm->Width; x += 32) {
  509.     p = dirty_list;
  510.     y0 = 0;
  511.     while (y0++ < e_bm->Height && !*p)
  512.       p += w32;
  513.     if (y0 < e_bm->Height) {
  514.       y0--;
  515.       p = dirty_list + h32;
  516.       y1 = e_bm->Height - 1;
  517.       while (!*p) {
  518.         p -= w32;
  519.         y1--;
  520.       }
  521.       EG_CopyBitMapRastPort (e_bm, eg_rp, x, y0, 32, y1 - y0 + 1, x, y0);
  522.     }
  523.     dirty_list++;
  524.   }
  525.  
  526. /*
  527.   UWORD d, x, y;
  528.  
  529.   x = 0;
  530.   y = 0;
  531.   for (d = plsiz >> 2; d > 0; d--) {
  532.     if (*dirty_list++ != 0)
  533.       EG_CopyBitMapRastPort (e_bm, eg_rp, x, y, 32, 1, x, y);
  534.     if ((x += 32) >= screen_width) {
  535.       x = 0;
  536.       y++;
  537.     }
  538.   }
  539. */
  540.  
  541. /*
  542.   EG_CopyBitMapRastPort (e_bm, eg_rp, 0, 0, e_bm->Width, e_bm->Height, 0, 0);
  543. */
  544. }
  545.  
  546. /****************************************************************************/
  547.  
  548. void decode_ss2 (UBYTE *chunkbuf, UBYTE *chunky, struct header *h,
  549.                  UBYTE *dirty_list)
  550. {
  551.   UWORD lines, packets, bsize, start;
  552.   ULONG tmp;
  553.   UBYTE *chunky2;
  554.  
  555.   lines = *chunkbuf++;
  556.   lines |= (*chunkbuf++ << 8);
  557.   for ( ; lines > 0; lines--) {
  558.     do {
  559.       packets = *chunkbuf++;
  560.       packets |= (*chunkbuf++ << 8);
  561.       if (packets > 32767)
  562.         if (packets > 49151) {
  563.           tmp = (65536 - packets) * (ULONG)screen_width;
  564.           chunky += tmp;
  565.           dirty_list += (tmp >> 5);
  566.         } else {
  567.           *(chunky + h->width - 1) = (packets & 0xff);
  568.           dirty_list[(h->width - 1) >> 5] = TRUE;
  569.         }
  570.     } while (packets >= 32768);
  571.     chunky2 = chunky;
  572.     for ( ; packets > 0; packets--) {
  573.       chunky2 += *chunkbuf++;
  574.       bsize = *chunkbuf++;
  575.       start = (chunky2 - chunky) >> 5;
  576.       if (bsize > 127) {
  577.         bsize = 256 - bsize;
  578. /*
  579.         repmem (chunky2, chunkbuf, 2, bsize);
  580.         chunky2 += (bsize << 1);
  581. */
  582.         for ( ; bsize > 0; bsize--) {
  583.           *chunky2++ = *chunkbuf;
  584.           *chunky2++ = *(chunkbuf + 1);
  585.         }
  586.         chunkbuf += 2;
  587.       } else {
  588.         bsize <<= 1;
  589.         memcpy (chunky2, chunkbuf, bsize);
  590. /*
  591.         CopyMem (chunkbuf, chunky2, bsize);
  592. */
  593.         chunkbuf += bsize;
  594.         chunky2 += bsize;
  595.       }
  596.       memset (&dirty_list[start], TRUE, ((chunky2-1 - chunky) >> 5) - start + 1);
  597.     }
  598.     chunky += screen_width;
  599.     dirty_list += screen_width32;
  600.   }
  601. }
  602.  
  603.  
  604. void decode_ss2_xlate (UBYTE *chunkbuf, UBYTE *chunky, struct header *h,
  605.                        UBYTE *xlate, UBYTE *dirty_list)
  606. {
  607.   UWORD lines, packets, bsize, start;
  608.   ULONG tmp;
  609.   UBYTE *chunky2, pattern[2];
  610.  
  611.   lines = *chunkbuf++;
  612.   lines |= (*chunkbuf++ << 8);
  613.   for ( ; lines > 0; lines--) {
  614.     do {
  615.       packets = *chunkbuf++;
  616.       packets |= (*chunkbuf++ << 8);
  617.       if (packets > 32767)
  618.         if (packets > 49151) {
  619.           tmp = (65536 - packets) * (ULONG)screen_width;
  620.           chunky += tmp;
  621.           dirty_list += (tmp >> 5);
  622.         } else {
  623.           *(chunky + h->width - 1) = xlate[packets & 0xff];
  624.           dirty_list[(h->width - 1) >> 5] = TRUE;
  625.         }
  626.     } while (packets >= 32768);
  627.     chunky2 = chunky;
  628.     for ( ; packets > 0; packets--) {
  629.       chunky2 += *chunkbuf++;
  630.       bsize = *chunkbuf++;
  631.       start = (chunky2 - chunky) >> 5;
  632.       if (bsize > 127) {
  633.         bsize = 256 - bsize;
  634.         pattern[0] = xlate[*chunkbuf++];
  635.         pattern[1] = xlate[*chunkbuf++];
  636. /*
  637.         repmem (chunky2, pattern, 2, bsize);
  638.         chunky2 += (bsize << 1);
  639. */
  640.         for ( ; bsize > 0; bsize--) {
  641.           *chunky2++ = pattern[0];
  642.           *chunky2++ = pattern[1];
  643.         }
  644.       } else {
  645.         bsize <<= 1;
  646.         for ( ; bsize > 0; bsize--)
  647.           *chunky2++ = xlate[*chunkbuf++];
  648.       }
  649.       memset (&dirty_list[start], TRUE, ((chunky2-1 - chunky) >> 5) - start + 1);
  650.     }
  651.     chunky += screen_width;
  652.     dirty_list += screen_width32;
  653.   }
  654. }
  655.  
  656.  
  657. #if 0
  658. void decode_lc (UBYTE *chunkbuf, UBYTE *chunky,
  659.                 UBYTE *xlate, enum mode_type mode, UBYTE *dirty_list)
  660. {
  661.   UBYTE *chunky2;
  662.   UWORD lines, packets, bsize, start;
  663.  
  664.   start = *chunkbuf++;
  665.   start |= (*chunkbuf++ << 8);
  666.   chunky = &chunky[start * screen_width];
  667.   dirty_list = &dirty_list[start * screen_width32];
  668.   lines = *chunkbuf++;
  669.   lines |= (*chunkbuf++ << 8);
  670.   for ( ; lines > 0; lines--) {
  671.     chunky2 = chunky;
  672.     for (packets = *chunkbuf++; packets > 0; packets--) {
  673.       chunky2 += *chunkbuf++;
  674.       bsize = *chunkbuf++;
  675.       start = (chunky2 - chunky) >> 5;
  676.       if (bsize > 127) {
  677.         bsize = 256 - bsize;
  678.         memset (chunky2, xlate[*chunkbuf++], bsize);
  679.         chunky2 += bsize;
  680.       } else {
  681.         if (mode == MODE_COLOUR) {
  682.           memcpy (chunky2, chunkbuf, bsize);
  683. /*
  684.           CopyMem (chunkbuf, chunky2, bsize);
  685. */
  686.           chunkbuf += bsize;
  687.           chunky2 += bsize;
  688.         } else
  689.           for ( ; bsize > 0; bsize--)
  690.             *chunky2++ = xlate[*chunkbuf++];
  691.       }
  692.       memset (&dirty_list[start], TRUE, ((chunky2-1 - chunky) >> 5) - start + 1);
  693.     }
  694.     chunky += screen_width;
  695.     dirty_list += screen_width32;
  696.   }
  697. }
  698. #endif
  699.  
  700. void decode_brun (UBYTE *chunkbuf, UBYTE *chunky, struct header *h,
  701.                   UBYTE *xlate, enum mode_type mode, UBYTE *dirty_list)
  702. {
  703.   UBYTE *chunky2;
  704.   UWORD lines, bsize;
  705.  
  706.   for (lines = h->height; lines > 0; lines--) {
  707.     chunky2 = chunky + h->width;
  708.     chunkbuf++;    /* skip packet count */
  709.     while (chunky < chunky2) {
  710.       bsize = *chunkbuf++;
  711.       if (bsize <= 127) {
  712.         memset (chunky, xlate[*chunkbuf++], bsize);
  713.         chunky += bsize;
  714.       } else {
  715.         bsize = 256 - bsize;
  716.         if (mode == MODE_COLOUR) {
  717.           memcpy (chunky, chunkbuf, bsize);
  718. /*
  719.           CopyMem (chunkbuf, chunky, bsize);
  720. */
  721.           chunkbuf += bsize;
  722.           chunky += bsize;
  723.         } else
  724.           for ( ; bsize > 0; bsize--)
  725.             *chunky++ = xlate[*chunkbuf++];
  726.       }
  727.     }
  728.     chunky += (screen_width - h->width);
  729.     memset (dirty_list, TRUE, ((h->width - 1) >> 5) + 1);
  730.     dirty_list += screen_width32;
  731.   }
  732. }
  733.  
  734.  
  735. /****************************************************************************/
  736.  
  737. int open_screen (char *fname, struct options *opt)
  738. {
  739.   int which, depth, nbytes;
  740.   DisplayInfoHandle handle;
  741.   struct NameInfo nameinfo;
  742.   char reqtitle[20];
  743.   static struct TagItem nstags[] = {
  744.     {SA_DisplayID,    0},
  745.     {TAG_DONE,        0}
  746.   };
  747.  
  748.   if (opt->mode == MODE_EGS) {
  749.  
  750.     if (EGSBase == NULL ||
  751.         EGSGfxBase == NULL ||
  752.         EGSBlitBase == NULL ||
  753.         EGSIntuiBase == NULL)
  754.       return (FALSE);
  755.  
  756.     /* open custom EGS screen using FLICK env var or screenmode req */
  757.     if ((ei_ns.Mode = getenv ("FLICK")) != NULL) {
  758.       if (stricmp (ei_ns.Mode, "DEFAULT") == 0) {
  759.         ei_nw.Screen = NULL; /* window will open on default EGS screen */
  760.       } else {
  761.         if ((ei_s = EI_OpenScreen (&ei_ns)) == NULL) {
  762.           fprintf (stderr, "Can't open \"%s\" EGS screen!\n", ei_ns.Mode);
  763.           return (FALSE);
  764.         }
  765.       }
  766.     } else if (smr != NULL) {
  767.       /* Put up screenmode requester */
  768.       sprintf (reqtitle, "Flick %dx%d", screen_width, h.height);
  769.       if (!AslRequestTags (smr,
  770.                            ASLSM_TitleText,     (ULONG)reqtitle,
  771.                            ASLSM_MinWidth,      screen_width,
  772.                            ASLSM_MinHeight,     h.height,
  773.                            ASLSM_MinDepth,      8,
  774.                            ASLSM_PropertyFlags, 0,
  775.                            TAG_DONE))
  776.         die ("%s: ScreenMode requester cancelled", programname);
  777.       /* Get the user-friendly name for selected mode in nameinfo.Name */
  778.       if ((handle = FindDisplayInfo (smr->sm_DisplayID)) == NULL) {
  779.         fprintf (stderr, "Can't FindDisplayInfo() for mode %08x\n",
  780.                  smr->sm_DisplayID);
  781.         return (FALSE);
  782.       }
  783.       if ((nbytes = GetDisplayInfoData (handle, (UBYTE *)&nameinfo,
  784.                                         sizeof(struct NameInfo), DTAG_NAME,
  785.                                         smr->sm_DisplayID)) < 48) {
  786.         fprintf (stderr, "Can't GetDisplayInfoData() for mode %08x, got %d bytes\n",
  787.                  smr->sm_DisplayID, nbytes);
  788.         return (FALSE);
  789.       }
  790.       /* open EGS screen with selected mode name */
  791.       ei_ns.Mode = nameinfo.Name;
  792.       if ((ei_s = EI_OpenScreen (&ei_ns)) == NULL) {
  793.         fprintf (stderr, "Can't open \"%s\" EGS screen!\n", ei_ns.Mode);
  794.         return (FALSE);
  795.       }
  796.     } else {
  797.       /* Otherwise use the default EGS screen */
  798.       ei_nw.Screen = NULL; /* window will open on default EGS screen */
  799.     }
  800.  
  801.  
  802.     /* open EGS window (may be on custom screen or default screen) */
  803.     if (ei_s != NULL) {
  804.       ei_nw.Screen = ei_s; /* window will open on custom EGS screen */
  805.       ei_nw.LeftEdge = (ei_s->Width - screen_width) >> 1;  /* center the window */
  806.       ei_nw.TopEdge = (ei_s->Height - h.height) >> 1; /* center the window */
  807.     }
  808.  
  809.     ei_nw.Width = screen_width;
  810.     ei_nw.Height = h.height;
  811.     ei_nw.Title = fname;
  812.     if ((ei_w = EI_OpenWindow (&ei_nw)) == NULL) {
  813.       close_screen ();
  814.       return (FALSE);
  815.     }
  816.     eg_rp = ei_w->RPort;
  817.  
  818.     if (ei_w->WScreen->EScreen->Map->Depth != 8) {
  819.       fprintf (stderr, "Default EGS screen is not depth 8!\n");
  820.       fprintf (stderr, "Use 'setenv FLICK \"egs-mode-name\"' to select another EGS mode\n");
  821.       close_screen ();
  822.       return (FALSE);
  823.     }
  824.  
  825.     if ((e_bm = E_AllocBitMap (screen_width, h.height, 8, E_PIXELMAP, 0, 0))
  826.                                                                      == NULL) {
  827.       close_screen ();
  828.       return (FALSE);
  829.     }
  830.     e_bm->Lock++;    /* ensure EGS system doesn't move bitmap memory */
  831.     chunky = e_bm->Plane;
  832.  
  833.   } else {
  834.     switch (opt->mode) {
  835.       case MODE_COLOUR:
  836.         if (!v39)
  837.           return (FALSE);
  838.         screen_depth = 8;
  839.         break;
  840.       case MODE_EHB:
  841.         ns.ViewModes |= EXTRA_HALFBRITE;
  842.         screen_depth = 6;
  843.         break;
  844.       case MODE_COLOUR4:
  845.       case MODE_GREY:
  846.         screen_depth = 4;
  847.       default:
  848.         break;
  849.     }
  850.     ns.Width = screen_width;
  851.     ns.Height = h.height;
  852.     ns.Depth = screen_depth;
  853.     if (screen_width > 384)
  854.       ns.ViewModes |= HIRES;
  855.     else
  856.       ns.ViewModes &= ~HIRES;
  857.     if (h.height > 283)
  858.       ns.ViewModes |= LACE;
  859.     else
  860.       ns.ViewModes &= ~LACE;
  861.  
  862.     /* allocate 2 rasters (for double-buffering) and initialise rp[] */
  863.     ns.Type &= ~NS_EXTENDED;
  864.     if (v39 && opt->rom) {
  865.       ns.Type &= ~CUSTOMBITMAP;  /* allow for mode promotion with ROM option */
  866.       ns.CustomBitMap = NULL;    /* i.e, no custom bitmap */
  867.       if (smr != NULL) {
  868.         /* Put up screenmode requester */
  869.         sprintf (reqtitle, "Flick %dx%d", screen_width, h.height);
  870.         if (!AslRequestTags (smr,
  871.                              ASLSM_TitleText,     (ULONG)reqtitle,
  872.                              ASLSM_MinWidth,      screen_width,
  873.                              ASLSM_MinHeight,     h.height,
  874.                              ASLSM_MinDepth,      screen_depth,
  875.                              ASLSM_PropertyFlags, (opt->mode == MODE_EHB) ?
  876.                                                    DIPF_IS_EXTRAHALFBRITE : 0,
  877.                              TAG_DONE))
  878.           die ("%s: ScreenMode requester cancelled", programname);
  879.         ns.Type |= NS_EXTENDED;
  880.         ns.Extension = nstags;
  881.         nstags[0].ti_Data = smr->sm_DisplayID;
  882.       }
  883.     } else {
  884.       ns.Type |= CUSTOMBITMAP;
  885.       ns.CustomBitMap = &screen_bm[0];
  886.       for (which = 0; which < (opt->dbuf ? 2 : 1); which++) {
  887.         InitBitMap (&screen_bm[which], screen_depth, screen_width, h.height); /* Displayed bm */
  888.         /* Allocate 1 contiguous raster for all screen_depth planes */
  889.         if ((raster[which] = (PLANEPTR)AllocRaster (screen_width,
  890.                                               screen_depth * h.height)) == NULL) {
  891.           close_screen ();
  892.           return (FALSE);
  893.         }
  894.         for (depth = 0; depth < screen_depth; depth++)
  895.           screen_bm[which].Planes[depth] = raster[which] +
  896.                                          depth * RASSIZE (screen_width, h.height);
  897.         InitRastPort (&rp[which]);
  898.         rp[which].BitMap = &screen_bm[which];
  899.         SetRast (&rp[which], 0);
  900.       }
  901.     }
  902.  
  903.     if ((s = OpenScreen((struct NewScreen *)&ns)) == NULL) {
  904.       close_screen ();
  905.       return (FALSE);
  906.     }
  907.  
  908.     /* allocate structures for double-buffering (if v39) */
  909.     if (v39 && opt->dbuf) {
  910.       if ((safeport = CreatePort (NULL, 0)) == NULL ||
  911.           (dispport = CreatePort (NULL, 0)) == NULL)
  912.         die ("%s: Can't create port!", programname);
  913.       if (opt->rom) {
  914.         if ((sb[0] = AllocScreenBuffer (s, NULL, SB_SCREEN_BITMAP)) == NULL ||
  915.             (sb[1] = AllocScreenBuffer (s, NULL, 0)) == NULL) {
  916.           fprintf (stderr, "Can't allocate structure for double buffering\n");
  917.           close_screen ();
  918.           return (FALSE);
  919.         }
  920.       } else {
  921.         if ((sb[0] = AllocScreenBuffer (s, &screen_bm[0], 0)) == NULL ||
  922.             (sb[1] = AllocScreenBuffer (s, &screen_bm[1], 0)) == NULL) {
  923.           fprintf (stderr, "Can't allocate structure for double buffering\n");
  924.           close_screen ();
  925.           return (FALSE);
  926.         }
  927.       }
  928.       sb[0]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = safeport;
  929.       sb[0]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = dispport;
  930.       sb[1]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = safeport;
  931.       sb[1]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = dispport;
  932.     }
  933.  
  934.     /* initialise rp[] for ROM option */
  935.     if (v39 && opt->rom) {
  936.       InitRastPort (&rp[0]);
  937.       rp[0].BitMap = s->RastPort.BitMap;
  938.       SetRast (&rp[0], 0);
  939.       if (opt->dbuf) {
  940.         InitRastPort (&rp[1]);
  941.         rp[1].BitMap = sb[1]->sb_BitMap;
  942.         SetRast (&rp[1], 0);
  943.       }
  944.     }
  945.  
  946.     /* open a backdrop window (for intuition events) */
  947.     nw.Width = screen_width;
  948.     nw.Height = h.height;
  949.     nw.Screen = s;
  950.     nw.MinWidth = screen_width;
  951.     nw.MinHeight = h.height;
  952.     nw.MaxWidth = screen_width;
  953.     nw.MaxHeight = h.height;
  954.     if ((w = OpenWindow(&nw)) == NULL) {
  955.       close_screen ();
  956.       return (FALSE);
  957.     }
  958.  
  959.     /* allocate chunky pixels */
  960.     if ((chunky = (UBYTE *)malloc (screen_width * (ULONG)h.height)) == NULL) {
  961.       close_screen ();
  962.       return (FALSE);
  963.     }
  964.  
  965.   }
  966.   memset (chunky, 0, screen_width * (ULONG)h.height);
  967.   return (TRUE);
  968. }
  969.  
  970. /****************************************************************************/
  971.  
  972. void parse_tooltypes (char *fname, struct options *opt)
  973. {
  974.   struct DiskObject *obj;
  975.   char **toolarray;
  976.  
  977.   if ((obj = GetDiskObject (fname)) != NULL) {
  978.     toolarray = obj->do_ToolTypes;
  979.     if (FindToolType (toolarray, "DISK") != NULL)
  980.       opt->ram = FALSE;
  981.     if (FindToolType (toolarray, "RAM") != NULL)
  982.       opt->ram = FALSE;
  983.     if (FindToolType (toolarray, "ONCE") != NULL)
  984.       opt->once = TRUE;
  985.     if (FindToolType (toolarray, "COLOUR") != NULL ||
  986.         FindToolType (toolarray, "COLOR") != NULL)
  987.       opt->mode = MODE_COLOUR;
  988.     if (FindToolType (toolarray, "EHB") != NULL)
  989.       opt->mode = MODE_EHB;
  990.     if (FindToolType (toolarray, "COLOUR4") != NULL ||
  991.         FindToolType (toolarray, "COLOR4") != NULL)
  992.       opt->mode = MODE_COLOUR4;
  993.     if (FindToolType (toolarray, "GREY") != NULL ||
  994.         FindToolType (toolarray, "GRAY") != NULL)
  995.       opt->mode = MODE_GREY;
  996.     if (FindToolType (toolarray, "EGS") != NULL)
  997.       opt->mode = MODE_EGS;
  998.     if (FindToolType (toolarray, "ROM") != NULL)
  999.       opt->rom = TRUE;
  1000.     if (FindToolType (toolarray, "DBUF") != NULL)
  1001.       opt->dbuf = TRUE;
  1002.     if (FindToolType (toolarray, "WARP") != NULL)
  1003.       opt->warp = TRUE;
  1004.     if (FindToolType (toolarray, "NOAKIKO") != NULL)
  1005.       opt->akiko = FALSE;
  1006.     FreeDiskObject (obj);
  1007.   }
  1008. }
  1009.  
  1010. /****************************************************************************/
  1011.  
  1012. void animate_file (char *fname, struct options opt)
  1013. {
  1014.   FILE *f;
  1015.   ULONG size, class, ei_class, totalframes, restartpos, l, *lp, *lp0, *lp1;
  1016.   UWORD i, frame, chunk, code, ei_code;
  1017.   UWORD packets, n, m, c, lines, depth, which;
  1018.   UWORD *viewcolourtable;
  1019.   UBYTE (*colourtable)[256][3];
  1020.   struct IntuiMessage *msg;
  1021.   struct EI_EIntuiMsg *ei_msg;
  1022.   UBYTE *filebuf, *buf, *framebuf, *chunkbuf, *p, *p2;
  1023.   UBYTE *dirty_list[2], *combined_dirty_list, *copy_of_chunky;
  1024.   UBYTE *restartptr, *xlate;
  1025.   BOOL going, firstloop;
  1026.   struct frameheader *fh;
  1027.   struct chunkheader *ch;
  1028.   ULONG fh_size;
  1029.   UWORD fh_magic, fh_chunks, ch_type;
  1030.   BOOL palette_changed;
  1031.   int oldpri;
  1032.   struct EClockVal eclocks, next_time;
  1033.   void __asm (*c2p)(register __a0 UBYTE *chunky_data,
  1034.                     register __a1 PLANEPTR raster,
  1035.                     register __a2 UBYTE *dirty_list,
  1036.                     register __d1 ULONG plsiz,
  1037.                     register __a5 UBYTE *tmp_buffer);
  1038.  
  1039.  
  1040.   /* initialise resources */
  1041.   f = NULL;
  1042.   viewcolourtable = NULL;
  1043.   filebuf = NULL;
  1044.   framebuf = NULL;
  1045.   dirty_list[0] = NULL;
  1046.   dirty_list[1] = NULL;
  1047.   combined_dirty_list = NULL;
  1048.   copy_of_chunky = NULL;
  1049.   xlate = NULL;
  1050.   colourtable = NULL;
  1051.   fh = NULL;
  1052.  
  1053.   parse_tooltypes (fname, &opt);
  1054.  
  1055.   if (opt.mode == MODE_EGS) {
  1056.     opt.dbuf = FALSE;
  1057.     opt.rom = FALSE;
  1058.   }
  1059.  
  1060.   /* open file and read header struct */
  1061.   if ((f = fopen (fname, "rb")) == NULL)
  1062.     die ("%s: Can't open %s", programname, fname);
  1063.   if ((fread (&h, sizeof(struct header), 1, f)) != 1)
  1064.     die ("%s: Error reading file", programname);
  1065.   swapl (&h.size);
  1066.   swapw (&h.magic);
  1067.   swapw (&h.frames);
  1068.   swapw (&h.width);
  1069.   swapw (&h.height);
  1070.   swapw (&h.depth);
  1071.   swapw (&h.flags);
  1072.   swapl (&h.speed);
  1073.   swapl (&h.creator);
  1074.   swapl (&h.updater);
  1075.   swapw (&h.aspectx);
  1076.   swapw (&h.aspecty);
  1077.   swapl (&h.oframe1);
  1078.   swapl (&h.oframe2);
  1079.  
  1080.   printf ("File = %s\n", fname);
  1081.   printf ("%lu bytes, %u frames, %ux%ux%u, speed = %u\n", h.size, h.frames,
  1082.           h.width, h.height, h.depth, h.speed);
  1083.  
  1084.   eclocks.ev_hi = 0;
  1085.   if (h.magic == 0xaf11) {
  1086.     eclocks.ev_lo = (ULONG)((1000000.0 / 70.0) * h.speed / micros_per_eclock + 0.5);
  1087.     if (h.speed != 0)
  1088.       printf ("Defined frames per second = %4.1lf", 70.0 / h.speed);
  1089.     putchar ('\n');
  1090.   } else if (h.magic == 0xaf12) {
  1091.     eclocks.ev_lo = (ULONG)((1000000.0 / 1000.0) * h.speed / micros_per_eclock + 0.5);
  1092.     if (h.speed != 0)
  1093.       printf ("Defined frames per second = %4.1lf", 1000.0 / h.speed);
  1094.     putchar ('\n');
  1095.   } else
  1096.     die ("%s: Unrecognised magic number %04x", programname, h.magic);
  1097.   if (opt.warp)
  1098.     eclocks.ev_lo = 0;
  1099.  
  1100.   /* allow for AGA modes */
  1101.   screen_width = (h.width + 63) & ~63;
  1102.   screen_width32 = (screen_width >> 5);
  1103.  
  1104.   /* allocate dirty lists */
  1105.   for (which = 0; which < (opt.dbuf ? 2 : 1); which++) {
  1106.     dirty_list[which] = malloc_check (screen_width32 * (ULONG)h.height + 8);
  1107.     memset (dirty_list[which], FALSE, screen_width32 * (ULONG)h.height + 8);
  1108.   }
  1109.  
  1110.   if (opt.dbuf) {
  1111.     combined_dirty_list = malloc_check (screen_width32 * (ULONG)h.height + 8);
  1112.     memset (combined_dirty_list, FALSE, screen_width32 * (ULONG)h.height + 8);
  1113.   } else
  1114.     combined_dirty_list = dirty_list[0];
  1115.  
  1116.   /* if using ram then read in the entire file else allocate header buffers */
  1117.   if (opt.ram)
  1118.     if ((filebuf = malloc (h.size - sizeof(struct header))) == NULL) {
  1119.       printf ("%s: Not enough free contiguous memory to load into RAM\n", programname);
  1120.       printf ("       Playing from disk instead\n");
  1121.       opt.ram = FALSE;
  1122.     } else {
  1123.       if ((fread (filebuf, h.size - sizeof(struct header), 1, f)) != 1)
  1124.         die ("%s: Error reading file", programname);
  1125.       buf = filebuf;
  1126.     }
  1127.   if (!opt.ram) {
  1128.     fh = malloc_check (sizeof(struct frameheader));
  1129.   }
  1130.  
  1131.   /* open screen with custom bitmap */
  1132.   while (!open_screen (fname, &opt)) {
  1133.     switch (opt.mode) {
  1134.       case MODE_COLOUR:
  1135.         printf ("%s: Can't open 8 bitplane COLOUR screen\n", programname);
  1136.         if (ns.ViewModes & HIRES) {
  1137.           printf ("       Trying 4 bitplane COLOUR4 instead\n");
  1138.           opt.mode = MODE_COLOUR4;
  1139.         } else {
  1140.           printf ("       Trying 6 bitplane EHB instead\n");
  1141.           opt.mode = MODE_EHB;
  1142.         }
  1143.         break;
  1144.       case MODE_EHB:
  1145.         printf ("%s: Can't open 6 bitplane EHB screen\n", programname);
  1146.         printf ("       Trying 4 bitplane COLOUR4 instead\n");
  1147.         opt.mode = MODE_COLOUR4;
  1148.         break;
  1149.       case MODE_EGS:
  1150.         printf ("%s: Can't open 8 bitplane EGS screen\n", programname);
  1151.         printf ("       Trying 8 bitplane COLOUR instead\n");
  1152.         opt.mode = MODE_COLOUR;
  1153.         break;
  1154.       case MODE_COLOUR4:
  1155.       case MODE_GREY:
  1156.       default:
  1157.         die ("%s: Can't open screen!", programname);
  1158.     }
  1159.     Delay (100);
  1160.   }
  1161.  
  1162.   /* initialise tmp stuff for WritePixelArray8() */
  1163.   if (opt.rom) {
  1164.     temprp = rp[0];
  1165.     temprp.Layer = NULL;
  1166.     if (v39) {
  1167.       if ((tmp_bm = AllocBitMap (screen_width, 1, screen_depth, BMF_CLEAR,
  1168.                                  rp[0].BitMap)) == NULL)
  1169.         die ("%s: Out of memory", programname);
  1170.     } else {
  1171.       if ((tmpras = (PLANEPTR)AllocRaster (screen_width, screen_depth))==NULL ||
  1172.           (tmp_bm = (struct BitMap *)AllocMem (sizeof(struct BitMap),
  1173.                                              MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  1174.         die ("%s: Out of memory", programname);
  1175.       InitBitMap (tmp_bm, screen_depth, screen_width, 1);
  1176.       for (depth = 0; depth < screen_depth; depth++)
  1177.         tmp_bm->Planes[depth] = tmpras + depth * RASSIZE (screen_width, 1);
  1178.     }
  1179.     temprp.BitMap = tmp_bm;
  1180.   }
  1181.  
  1182.   /* turn the mouse pointer off for this window */
  1183.   if (opt.mode != MODE_EGS)
  1184.     SetPointer (w, emptypointer, 1, 16, 0, 0);
  1185.  
  1186.   /* allocate and initialise colour tables and pixel xlate table */
  1187.   colourtable = (UBYTE (*)[256][3])malloc_check (sizeof(*colourtable));
  1188.   memset (colourtable, 0, sizeof(*colourtable));
  1189.   xlate = malloc_check (256);
  1190.  
  1191.   switch (opt.mode) {
  1192.     case MODE_COLOUR4:
  1193.     case MODE_EHB:
  1194.       viewcolourtable = (UWORD *)malloc_check ((1 << screen_depth) * sizeof(UWORD));
  1195.       memset (viewcolourtable, 0, (1 << screen_depth) * sizeof(UWORD));
  1196.       break;
  1197.     case MODE_GREY:
  1198.       viewcolourtable = (UWORD *)malloc_check ((1 << screen_depth) * sizeof(UWORD));
  1199.       memset (viewcolourtable, 0, (1 << screen_depth) * sizeof(UWORD));
  1200.       for (c = 0; c < 16; c++)
  1201.         viewcolourtable[c] = c * 0x0111;
  1202.       LoadRGB4 (&s->ViewPort, viewcolourtable, 1 << screen_depth);
  1203.       break;
  1204.     case MODE_COLOUR:
  1205.       viewcolourtable = (UWORD *)malloc_check (2 * sizeof(UWORD) +
  1206.                        (1 << screen_depth) * 3 * sizeof(ULONG) + sizeof(UWORD));
  1207.       memset (viewcolourtable, 0, 2 * sizeof(UWORD) +
  1208.                        (1 << screen_depth) * 3 * sizeof(ULONG) + sizeof(UWORD));
  1209.       viewcolourtable[0] = 1 << screen_depth;
  1210.       for (i = 0; i < 256; i++)
  1211.         xlate[i] = i;
  1212.       break;
  1213.     case MODE_EGS:
  1214.       e_screencolours = (E_CLU *)malloc_check (256 * sizeof(E_CLU));
  1215.       e_oldscreencolours = (E_CLU *)malloc_check (256 * sizeof(E_CLU));
  1216.       E_GetRGB8CM (ei_w->WScreen->EScreen, e_oldscreencolours, 0, 256);
  1217.       E_GetRGB8CM (ei_w->WScreen->EScreen, e_screencolours, 0, 256);
  1218.       for (i = 0; i < 256; i++)
  1219.         xlate[i] = i;
  1220.       break;
  1221.   }
  1222.  
  1223.   /* select a chunky to planar (c2p) routine */
  1224.   if (opt.mode != MODE_EGS) {
  1225.     if (opt.rom) {
  1226.       copy_of_chunky = malloc_check (screen_width * (ULONG)h.height);
  1227.     } else if (v40 && opt.akiko && (GfxBase->ChunkyToPlanarPtr != NULL)) {
  1228.       copy_of_chunky = (UBYTE *)GfxBase->ChunkyToPlanarPtr;
  1229.       switch (screen_depth) {
  1230.         case 4:
  1231.           c2p = c2p_4_akiko;
  1232.           break;
  1233.         case 6:
  1234.           c2p = c2p_6_akiko;
  1235.           break;
  1236.         case 8:
  1237.           c2p = c2p_8_akiko;
  1238.           break;
  1239.         default:
  1240.           die ("%s: Unsupported resolution", programname);
  1241.           break;
  1242.       }
  1243.     } else {
  1244.       switch (cpu_type) {
  1245.         case 68000:
  1246.         case 68010:
  1247.           switch (screen_depth) {
  1248.             case 4:
  1249.               c2p = c2p_4_000;
  1250.               break;
  1251.             case 6:
  1252.               c2p = c2p_6_000;
  1253.               break;
  1254.             case 8:
  1255.               c2p = c2p_8_000;
  1256.               break;
  1257.             default:
  1258.               die ("%s: Unsupported resolution", programname);
  1259.               break;
  1260.           }
  1261.           break;
  1262.         case 68020:
  1263.         case 68030:
  1264.           copy_of_chunky = malloc_check (screen_width * (ULONG)h.height);
  1265.           switch (screen_depth) {
  1266.             case 4:
  1267.               c2p = c2p_4_020;
  1268.               break;
  1269.             case 6:
  1270.               c2p = c2p_6_020;
  1271.               break;
  1272.             case 8:
  1273.               c2p = c2p_8_020;
  1274.               break;
  1275.             default:
  1276.               die ("%s: Unsupported resolution", programname);
  1277.               break;
  1278.           }
  1279.           break;
  1280.         case 68040:
  1281.         case 68060:
  1282.           switch (screen_depth) {
  1283.             case 4:
  1284.               c2p = c2p_4_040;
  1285.               break;
  1286.             case 6:
  1287.               c2p = c2p_6_040;
  1288.               break;
  1289.             case 8:
  1290.               c2p = c2p_8_040;
  1291.               break;
  1292.             default:
  1293.               die ("%s: Unsupported resolution", programname);
  1294.               break;
  1295.           }
  1296.           break;
  1297.         default:
  1298.           die ("%s: Unsupported CPU type %d", programname, cpu_type);
  1299.       }
  1300.     }
  1301.   }
  1302.  
  1303.   /* initialise loop variables */
  1304.   which = 0;    /* bitmap index --- flips between 0 and 1 with each frame */
  1305.   palette_changed = FALSE;
  1306.   frame = 0;
  1307.   totalframes = 0;
  1308.   firstloop = TRUE;
  1309.   going = TRUE;
  1310.  
  1311.   /* read the start time */
  1312.   ReadEClock (time0);
  1313.   next_time = *time0;
  1314.   add64 (&next_time, &eclocks);
  1315.  
  1316.   /* loop for each frame */
  1317.   while (going) {
  1318.  
  1319.     /* if this is the 2nd frame, save the current file-position for loop */
  1320.     if (totalframes == 1)
  1321.       if (opt.ram)
  1322.         restartptr = buf;
  1323.       else
  1324.         if ((restartpos = ftell (f)) == -1)
  1325.           die ("%s: Error ftelling file", programname);
  1326.  
  1327.     /* read the frame header */
  1328.     if (opt.ram) {
  1329.       fh = (struct frameheader *)buf;
  1330.       buf += sizeof(struct frameheader);
  1331.     } else
  1332.       if ((fread (fh, sizeof(struct frameheader), 1, f)) != 1)
  1333.         die ("%s: Error reading file", programname);
  1334.     if (firstloop || !opt.ram) {
  1335.       swapl (&fh->size);
  1336.       swapw (&fh->magic);
  1337.       swapw (&fh->chunks);
  1338.     }
  1339.     fh_size = extractl (&fh->size);
  1340.     fh_magic = extractw (&fh->magic);
  1341.     fh_chunks = extractw (&fh->chunks);
  1342.  
  1343.     /* allocate memory for and read the rest of the frame */
  1344.     if (opt.ram) {
  1345.       framebuf = buf;
  1346.     } else {
  1347.       size = fh_size - sizeof(struct frameheader);
  1348.       if (size == 0)
  1349.         framebuf = NULL;
  1350.       else {
  1351.         framebuf = malloc_check (size);
  1352.         if ((fread (framebuf, size, 1, f)) != 1)
  1353.           die ("%s: Error reading file", programname);
  1354.         buf = framebuf;
  1355.       }
  1356.     }
  1357.  
  1358.     /* check for and ignore 0xf100 frames */
  1359.     if (fh_magic == 0xf100) {
  1360.  
  1361.       totalframes--;    /* don't count this frame */
  1362.       frame--;
  1363.  
  1364.     } else {
  1365.  
  1366.       /* consistency check */
  1367.       if (fh_magic != 0xf1fa)
  1368.         die ("%s: Unrecognised magic number in frame %04x %lu",
  1369.                  programname, fh_magic, fh_size);
  1370.  
  1371.       /* render into the non-displayed raster (if double-buffering) */
  1372.       if (opt.dbuf)
  1373.         which = 1 - which;
  1374.  
  1375.       /* clear the dirty list for this frame */
  1376.       memset (dirty_list[which], FALSE, screen_width32 * (ULONG)h.height);
  1377.  
  1378.       /* loop for each chunk */
  1379.       for (chunk = 0; chunk < fh_chunks; chunk++) {
  1380.  
  1381.         /* examine the chunk header */
  1382.         ch = (struct chunkheader *)buf;
  1383.         if (firstloop || !opt.ram) {
  1384.           swapl (&ch->size);
  1385.           swapw (&ch->type);
  1386.         }
  1387.         chunkbuf = buf + sizeof(struct chunkheader);
  1388.         buf += (extractl (&ch->size) + 1) & ~1;
  1389.         ch_type = extractw (&ch->type);
  1390.  
  1391.         /* uncompress chunk into chunky pixels */
  1392.         switch (ch_type) {
  1393.  
  1394.           case FLI_SS2:
  1395.             if (opt.mode == MODE_COLOUR || opt.mode == MODE_EGS)
  1396.               decode_ss2 (chunkbuf, chunky, &h, dirty_list[which]);
  1397.             else
  1398.               decode_ss2_xlate (chunkbuf, chunky, &h, xlate, dirty_list[which]);
  1399.             break;
  1400.  
  1401.           case FLI_256_COLOR:
  1402.           case FLI_COLOR:
  1403.             p = chunkbuf;
  1404.             packets = *p++;
  1405.             packets |= (*p++ << 8);
  1406.             c = 0;
  1407.             for ( ; packets > 0; packets--) {
  1408.               c += *p++;
  1409.               n = *p++;
  1410.               if (n == 0)
  1411.                 n = 256;
  1412.               for (m = 0; m < n; m++) {
  1413.                 if (ch_type == FLI_256_COLOR) {
  1414.                   (*colourtable)[c][0] = *p++;        /* R */
  1415.                   (*colourtable)[c][1] = *p++;        /* G */
  1416.                   (*colourtable)[c][2] = *p++;        /* B */
  1417.                 } else {
  1418.                   (*colourtable)[c][0] = *p++ << 2;    /* R */
  1419.                   (*colourtable)[c][1] = *p++ << 2;    /* G */
  1420.                   (*colourtable)[c][2] = *p++ << 2;    /* B */
  1421.                 }
  1422.                 c++;
  1423.               }
  1424.             }
  1425.             switch (opt.mode) {
  1426.               case MODE_COLOUR4:
  1427.               case MODE_EHB:
  1428.                 median_cut (*colourtable, viewcolourtable, xlate, opt.mode);
  1429.                 break;
  1430.               case MODE_GREY:
  1431.                 for (c = 0; c < 256; c++)
  1432.                   xlate[c] = ((((UWORD)(*colourtable)[c][0]) +
  1433.                                ((UWORD)(*colourtable)[c][1]) +
  1434.                                ((UWORD)(*colourtable)[c][2])) / 3) >> 4;
  1435.                 break;
  1436.               case MODE_COLOUR:
  1437.                 break;
  1438.               case MODE_EGS:
  1439.                 for (c = 0; c < 256; c++) {
  1440.                   e_screencolours[c].Red = (*colourtable)[c][0];
  1441.                   e_screencolours[c].Green = (*colourtable)[c][1];
  1442.                   e_screencolours[c].Blue = (*colourtable)[c][2];
  1443.                 }
  1444.                 break;
  1445.             }
  1446.             palette_changed = TRUE;
  1447.             break;            
  1448.  
  1449.           case FLI_LC:
  1450.             if (opt.mode == MODE_COLOUR || opt.mode == MODE_EGS)
  1451.               decode_lc (chunkbuf, chunky, dirty_list[which]);
  1452.             else
  1453.               decode_lc_xlate (chunkbuf, chunky, xlate, dirty_list[which]);
  1454.             break;
  1455.  
  1456.           case FLI_BLACK:
  1457.             memset (chunky, xlate[0], screen_width * (ULONG)h.height);
  1458.             memset (dirty_list[which], TRUE, screen_width32 * (ULONG)h.height);
  1459.             break;
  1460.  
  1461.           case FLI_BRUN:
  1462.             decode_brun (chunkbuf, chunky, &h, xlate, opt.mode,
  1463.                          dirty_list[which]);
  1464.             break;
  1465.  
  1466.           case FLI_COPY:
  1467.             if (opt.mode == MODE_COLOUR || opt.mode == MODE_EGS)
  1468.               if (h.width == screen_width) {
  1469. /*
  1470.                 memcpy (chunky, chunkbuf, h.width * (ULONG)h.height);
  1471. */
  1472.                 CopyMemQuick (chunkbuf, chunky, screen_width * (ULONG)h.height);
  1473.               } else {
  1474.                 p = chunkbuf;
  1475.                 p2 = chunky;
  1476.                 for (lines = h.height; lines > 0; lines--) {
  1477.                   CopyMemQuick (p, p2, h.width);
  1478.                   p += h.width;
  1479.                   p2 += screen_width;
  1480.                 }
  1481.               }
  1482.             else {
  1483.               if (h.width == screen_width) {
  1484.                 p2 = chunky;
  1485.                 for (l = h.width * (ULONG)h.height; l > 0; l--)
  1486.                   *p2++ = xlate[*p++];
  1487.               } else {
  1488.                 p = chunkbuf;
  1489.                 p2 = chunky;
  1490.                 for (lines = h.height; lines > 0; lines--) {
  1491.                   for (i = h.width; i > 0; i--)
  1492.                     *p2++ = xlate[*p++];
  1493.                   p2 += (screen_width - h.width);
  1494.                 }
  1495.               }
  1496.             }
  1497.             memset (dirty_list[which], TRUE, screen_width32 * (ULONG)h.height);
  1498.             break;
  1499.  
  1500.           case FLI_PSTAMP:
  1501.             break;
  1502.  
  1503.           default:
  1504.             die ("%s: Unrecognised chunk type %04x", programname, ch_type);
  1505.             break;
  1506.         } /* end of switch for each chunk type */
  1507.  
  1508.       } /* end of loop for each chunk within frame */
  1509.  
  1510.       /* if double-buffering, combine the dirty lists */
  1511.       if (opt.dbuf) {
  1512.         lp0 = (ULONG *)dirty_list[which];
  1513.         lp1 = (ULONG *)dirty_list[1 - which];
  1514.         lp = (ULONG *)combined_dirty_list;
  1515.         for (l = ((screen_width32 * (ULONG)h.height) >> 2) + 1; l > 0; l--)
  1516.           *lp++ = *lp0++ | *lp1++;
  1517.       }
  1518.  
  1519.       /* update amiga's colourtable if palette has changed in this frame */
  1520.       if (palette_changed) {
  1521.         switch (opt.mode) {
  1522.           case MODE_COLOUR4:
  1523.             LoadRGB4 (&s->ViewPort, viewcolourtable, 16);
  1524.             break;
  1525.           case MODE_EHB:
  1526.             LoadRGB4 (&s->ViewPort, viewcolourtable, 32);
  1527.             break;
  1528.           case MODE_GREY:
  1529.             break;
  1530.           case MODE_COLOUR:
  1531.             for (c = 0; c < (1 << screen_depth); c++) {
  1532.               ((ULONG *)viewcolourtable)[3*c+1] = (*colourtable)[c][0] << 24;
  1533.               ((ULONG *)viewcolourtable)[3*c+2] = (*colourtable)[c][1] << 24;
  1534.               ((ULONG *)viewcolourtable)[3*c+3] = (*colourtable)[c][2] << 24;
  1535.             }
  1536.             LoadRGB32 (&s->ViewPort, (ULONG *)viewcolourtable);
  1537.             break;
  1538.           case MODE_EGS:
  1539.             E_SetRGB8CM (ei_w->WScreen->EScreen, e_screencolours, 0, 256);
  1540.             break;
  1541.         }
  1542.         palette_changed = FALSE;
  1543.       }
  1544.  
  1545.       /* Wait until it is safe to modify bitmap without flicker (if v39) */
  1546.       /* Allow CTRL_C escape to workaround flaw in CyBERgraphics */
  1547.       if (v39 && opt.dbuf) {
  1548.         if (!safe) {
  1549.           if ((Wait ((1 << safeport->mp_SigBit) | SIGBREAKF_CTRL_C)
  1550.                                                      & SIGBREAKF_CTRL_C) != 0) {
  1551.             printf ("***Break\n");
  1552.             safe = TRUE;  /* prevent further Wait() in cleanup */
  1553.             disp = TRUE;
  1554.             exit (0);
  1555.           }
  1556.           while (GetMsg (safeport) != NULL) /* clear message queue */
  1557.             /* nothing */ ;
  1558.           safe = TRUE;
  1559.         }
  1560.       }
  1561.  
  1562.       /* convert from chunky pixels to (hidden) planar raster[which] */
  1563.       if (opt.mode == MODE_EGS)
  1564.         c2p_egs (e_bm, eg_rp, combined_dirty_list,
  1565.                  (screen_width * (ULONG)h.height) >> 3);
  1566. /*
  1567.         EG_CopyBitMapRastPort (e_bm, eg_rp, 0, 0, screen_width, h.height, 0, 0);
  1568. */
  1569.       else if (opt.rom) {
  1570.         /* WritePixelArray8() destroys original chunky, so make a copy */
  1571. /*
  1572.         CopyMemQuick (chunky, copy_of_chunky, screen_width * (ULONG)h.height);
  1573.         WritePixelArray8 (&rp[which], 0, 0, screen_width-1, h.height-1,
  1574.                           copy_of_chunky, &temprp);
  1575.  
  1576. */
  1577.         c2p_rom (chunky, copy_of_chunky, &rp[which], &temprp,
  1578.                  combined_dirty_list);
  1579.       } else
  1580.         c2p (chunky, raster[which], combined_dirty_list,
  1581.              (screen_width * (ULONG)h.height) >> 3, copy_of_chunky);
  1582.  
  1583.       /* wait for time between frames */
  1584.       ReadEClock (time);
  1585.       if (cmp64 (time, &next_time) > 0) {
  1586.         timerio->tr_node.io_Command = TR_ADDREQUEST;
  1587.         *(struct EClockVal *)&timerio->tr_time = next_time;
  1588.         sub64 ((struct EClockVal *)&timerio->tr_time, time); /* timerio->tr_time -= time */
  1589.         /* oldpri = SetTaskPri (thistask, 20); */ /* don't flicker when mouse moves */
  1590.         DoIO ((struct IORequest *)timerio);  /* delay */
  1591.         /* SetTaskPri (thistask, oldpri); */ /* restore task priority */
  1592.       }
  1593.       while (cmp64 (time, &next_time) > 0) {
  1594.         ReadEClock (time);
  1595.       }
  1596.       next_time = *time;
  1597.       add64 (&next_time, &eclocks);
  1598.  
  1599.       /* make the new raster visible (if double-buffering) */
  1600.       if (opt.dbuf) {
  1601.         if (v39) {
  1602.           oldpri = SetTaskPri (thistask, 20); /* don't flicker when mouse moves */
  1603.           /* Wait until it is safe to swap bitmaps without flicker or CTRL_C */
  1604.           if (!disp) {
  1605.             if ((Wait ((1 << dispport->mp_SigBit) | SIGBREAKF_CTRL_C)
  1606.                                                      & SIGBREAKF_CTRL_C) != 0) {
  1607.               SetTaskPri (thistask, oldpri); /* restore task priority */
  1608.               printf ("***Break\n");
  1609.               safe = TRUE;  /* prevent further Wait() in cleanup */
  1610.               disp = TRUE;
  1611.               exit (0);
  1612.             }
  1613.             while (GetMsg (dispport) != NULL) /* clear message queue */
  1614.               /* nothing */ ;
  1615.             disp = TRUE;
  1616.           }
  1617.           if (ChangeScreenBuffer (s, sb[which])) {
  1618.             disp = FALSE;
  1619.             safe = FALSE;
  1620.           }
  1621.           SetTaskPri (thistask, oldpri); /* restore task priority */
  1622.         } else {
  1623.           s->ViewPort.RasInfo->BitMap = &screen_bm[which];
  1624.           MakeScreen (s);
  1625.           RethinkDisplay ();
  1626.         }
  1627.       }
  1628.  
  1629.       /* check for CTRL/C or BREAK */
  1630.       if (SetSignal (0, 0) & SIGBREAKF_CTRL_C) {
  1631.         SetSignal (0, SIGBREAKF_CTRL_C);
  1632.         printf ("***Break\n");
  1633.         exit (0);
  1634.       }
  1635.  
  1636.       /* check for intuition messages */
  1637.       if (opt.mode == MODE_EGS) {
  1638.         while ((ei_msg = (struct EI_EIntuiMsg *)GetMsg (ei_w->UserPort)) != NULL) {
  1639.           ei_class = ei_msg->Class;
  1640.           ei_code = ei_msg->Code;
  1641.           ReplyMsg ((struct Message *)ei_msg);
  1642.           switch (ei_class) {
  1643.             case EI_iRAWKEY:
  1644.               switch (ei_code) {
  1645.                 case 0x45: /* ESC */
  1646.                   going = FALSE;
  1647.                   break;
  1648.                 case 0x50: /* F1 */
  1649.                   eclocks.ev_lo = 0;
  1650.                   break;
  1651.                 case 0x51: /* F2 */
  1652.                   eclocks.ev_lo = (ULONG)((1000000.0 / 60.0) / micros_per_eclock + 0.5);
  1653.                   break;
  1654.                 case 0x52: /* F3 */
  1655.                   eclocks.ev_lo = (ULONG)((1000000.0 / 30.0) / micros_per_eclock + 0.5);
  1656.                   break;
  1657.                 case 0x53: /* F4 */
  1658.                   eclocks.ev_lo = (ULONG)((1000000.0 / 24.0) / micros_per_eclock + 0.5);
  1659.                   break;
  1660.                 case 0x54: /* F5 */
  1661.                   eclocks.ev_lo = (ULONG)((1000000.0 / 15.0) / micros_per_eclock + 0.5);
  1662.                   break;
  1663.                 case 0x55: /* F6 */
  1664.                   eclocks.ev_lo = (ULONG)((1000000.0 / 12.0) / micros_per_eclock + 0.5);
  1665.                   break;
  1666.                 case 0x56: /* F7 */
  1667.                   eclocks.ev_lo = (ULONG)((1000000.0 / 10.0) / micros_per_eclock + 0.5);
  1668.                   break;
  1669.                 case 0x57: /* F8 */
  1670.                   eclocks.ev_lo = (ULONG)((1000000.0 / 5.0) / micros_per_eclock + 0.5);
  1671.                   break;
  1672.                 case 0x58: /* F9 */
  1673.                   eclocks.ev_lo = (ULONG)(1000000.0 / micros_per_eclock + 0.5);
  1674.                   break;
  1675.                 case 0x59: /* F10 */
  1676.                   if (h.magic == 0xaf11)
  1677.                     eclocks.ev_lo = (ULONG)((1000000.0 / 70.0) * h.speed /
  1678.                                      micros_per_eclock + 0.5);
  1679.                   else if (h.magic == 0xaf12)
  1680.                     eclocks.ev_lo = (ULONG)((1000000.0 / 1000.0) * h.speed /
  1681.                                      micros_per_eclock + 0.5);
  1682.                   break;
  1683.                 default:
  1684.                   break;
  1685.               }
  1686.               break;
  1687.             case EI_iVANILLAKEY:
  1688.               switch (ei_code) {
  1689.                 case 0x03: /* CTRL/C */
  1690.                   printf ("***Break\n");
  1691.                   exit (0);
  1692.                 case 0x1b: /* ESC */
  1693.                 case 0x51: /* q */
  1694.                 case 0x71: /* Q */
  1695.                   going = FALSE;
  1696.                   break;
  1697.                 case '+':
  1698.                   if (eclocks.ev_lo == 1)
  1699.                     eclocks.ev_lo = 0;
  1700.                   else
  1701.                     eclocks.ev_lo >>= 1;
  1702.                   break;
  1703.                 case '-':
  1704.                   if (eclocks.ev_lo == 0)
  1705.                     eclocks.ev_lo = 1;
  1706.                   else if (eclocks.ev_lo < 500000)
  1707.                     eclocks.ev_lo <<= 1;
  1708.                   break;
  1709.                 default:
  1710.                   break;
  1711.               }
  1712.               break;
  1713.             case EI_iCLOSEWINDOW:
  1714.               going = FALSE;
  1715.               break;
  1716.             case EI_iMOUSEBUTTONS:
  1717.               if (ei_code == MENUDOWN)
  1718.                   going = FALSE;
  1719.               break;
  1720.             case EI_iACTIVEWINDOW:
  1721.               E_SetRGB8CM (ei_w->WScreen->EScreen, e_screencolours, 0, 256);
  1722.               break;
  1723.             case EI_iINACTIVEWINDOW:
  1724.               E_SetRGB8CM (ei_w->WScreen->EScreen, e_oldscreencolours, 0, 256);
  1725.               break;
  1726.             default:
  1727.               break;
  1728.           }
  1729.         }
  1730.       } else {
  1731.         while ((msg = (struct IntuiMessage *)GetMsg (w->UserPort)) != NULL) {
  1732.           class = msg->Class;
  1733.           code = msg->Code;
  1734.           ReplyMsg ((struct Message *)msg);
  1735.           switch (class) {
  1736.             case IDCMP_RAWKEY:
  1737.               switch (code) {
  1738.                 case 0x45: /* ESC */
  1739.                   going = FALSE;
  1740.                   break;
  1741.                 case 0x50: /* F1 */
  1742.                   eclocks.ev_lo = 0;
  1743.                   break;
  1744.                 case 0x51: /* F2 */
  1745.                   eclocks.ev_lo = (ULONG)((1000000.0 / 60.0) / micros_per_eclock + 0.5);
  1746.                   break;
  1747.                 case 0x52: /* F3 */
  1748.                   eclocks.ev_lo = (ULONG)((1000000.0 / 30.0) / micros_per_eclock + 0.5);
  1749.                   break;
  1750.                 case 0x53: /* F4 */
  1751.                   eclocks.ev_lo = (ULONG)((1000000.0 / 24.0) / micros_per_eclock + 0.5);
  1752.                   break;
  1753.                 case 0x54: /* F5 */
  1754.                   eclocks.ev_lo = (ULONG)((1000000.0 / 15.0) / micros_per_eclock + 0.5);
  1755.                   break;
  1756.                 case 0x55: /* F6 */
  1757.                   eclocks.ev_lo = (ULONG)((1000000.0 / 12.0) / micros_per_eclock + 0.5);
  1758.                   break;
  1759.                 case 0x56: /* F7 */
  1760.                   eclocks.ev_lo = (ULONG)((1000000.0 / 10.0) / micros_per_eclock + 0.5);
  1761.                   break;
  1762.                 case 0x57: /* F8 */
  1763.                   eclocks.ev_lo = (ULONG)((1000000.0 / 5.0) / micros_per_eclock + 0.5);
  1764.                   break;
  1765.                 case 0x58: /* F9 */
  1766.                   eclocks.ev_lo = (ULONG)(1000000.0 / micros_per_eclock + 0.5);
  1767.                   break;
  1768.                 case 0x59: /* F10 */
  1769.                   if (h.magic == 0xaf11)
  1770.                     eclocks.ev_lo = (ULONG)((1000000.0 / 70.0) * h.speed /
  1771.                                      micros_per_eclock + 0.5);
  1772.                   else if (h.magic == 0xaf12)
  1773.                     eclocks.ev_lo = (ULONG)((1000000.0 / 1000.0) * h.speed /
  1774.                                      micros_per_eclock + 0.5);
  1775.                   break;
  1776.                 default:
  1777.                   break;
  1778.               }
  1779.               break;
  1780.             case IDCMP_VANILLAKEY:
  1781.               switch (code) {
  1782.                 case 0x03: /* CTRL/C */
  1783.                   printf ("***Break\n");
  1784.                   exit (0);
  1785.                 case 0x1b: /* ESC */
  1786.                 case 0x51: /* q */
  1787.                 case 0x71: /* Q */
  1788.                   going = FALSE;
  1789.                   break;
  1790.                 case '+':
  1791.                   if (eclocks.ev_lo == 1)
  1792.                     eclocks.ev_lo = 0;
  1793.                   else
  1794.                     eclocks.ev_lo >>= 1;
  1795.                   break;
  1796.                 case '-':
  1797.                   if (eclocks.ev_lo == 0)
  1798.                     eclocks.ev_lo = 1;
  1799.                   else if (eclocks.ev_lo < 500000)
  1800.                     eclocks.ev_lo <<= 1;
  1801.                   break;
  1802.                 default:
  1803.                   break;
  1804.               }
  1805.             case IDCMP_MOUSEBUTTONS:
  1806.               if (code == MENUDOWN)
  1807.                   going = FALSE;
  1808.               break;
  1809.             default:
  1810.               break;
  1811.           }
  1812.         }
  1813.       }
  1814.  
  1815.     } /* end of if frame magic != 0xf100 */
  1816.  
  1817.     /* seek to the beginning of the next frame or deallocate frame ram */
  1818.     if (opt.ram)
  1819.       buf = framebuf + fh_size - sizeof(struct frameheader);
  1820.     else
  1821.       if (framebuf != NULL)
  1822.         free (framebuf);
  1823.     framebuf = NULL;
  1824.  
  1825.     /* seek back to frame 1 (the 2nd frame) when we get to the last frame */
  1826.     if (frame++ == h.frames)
  1827.       if (opt.once)
  1828.         going = FALSE;
  1829.       else {
  1830.         firstloop = FALSE;
  1831.         frame = 1;
  1832.         if (opt.ram)
  1833.           buf = restartptr;
  1834.         else
  1835.           if (fseek (f, restartpos, SEEK_SET) == -1)
  1836.             die ("%s: Error seeking file", programname);
  1837.       }
  1838.  
  1839.     totalframes++;
  1840.  
  1841.   } /* end of loop for each frame */
  1842.  
  1843.   if (!safe) {
  1844.     Wait (1 << safeport->mp_SigBit | SIGBREAKF_CTRL_C);
  1845.     while (GetMsg (safeport) != NULL) /* clear message queue */
  1846.       /* nothing */ ;
  1847.     safe = TRUE;
  1848.   }
  1849.   if (!disp) {
  1850.     Wait (1 << dispport->mp_SigBit | SIGBREAKF_CTRL_C);
  1851.     while (GetMsg (dispport) != NULL) /* clear message queue */
  1852.       /* nothing */ ;
  1853.     disp = TRUE;
  1854.   }
  1855.  
  1856.   /* find out and display how long it took */
  1857.   ReadEClock (time1);
  1858.   sub64 (time1, time0);
  1859.   printf ("%s: Achieved frames per second = %4.1lf\n", programname,
  1860.           1000000.0 * totalframes /
  1861.           ((time1->ev_hi * 4294967296.0 + time1->ev_lo) * micros_per_eclock));
  1862.  
  1863.   /* close files and free memory */
  1864.   if (f != NULL) {
  1865.     fclose (f);
  1866.     f = NULL;
  1867.   }
  1868.   close_screen ();
  1869.   if (colourtable != NULL) {
  1870.     free (colourtable);
  1871.     colourtable = NULL;
  1872.   }
  1873.   if (viewcolourtable != NULL) {
  1874.     free (viewcolourtable);
  1875.     viewcolourtable = NULL;
  1876.   }
  1877.   if (xlate != NULL) {
  1878.     free (xlate);
  1879.     xlate = NULL;
  1880.   }
  1881.   if (filebuf != NULL) {
  1882.     free (filebuf);
  1883.     filebuf = NULL;
  1884.   }
  1885.   if (!opt.ram) {
  1886.     if (fh != NULL) {
  1887.       free (fh);
  1888.       fh = NULL;
  1889.     }
  1890.   }
  1891.   if (opt.dbuf)
  1892.     if (combined_dirty_list != NULL) {
  1893.       free (combined_dirty_list);
  1894.       combined_dirty_list = NULL;
  1895.     }
  1896.   if (dirty_list[1] != NULL) {
  1897.     free (dirty_list[1]);
  1898.     dirty_list[1] = NULL;
  1899.   }
  1900.   if (dirty_list[0] != NULL) {
  1901.     free (dirty_list[0]);
  1902.     dirty_list[0] = NULL;
  1903.   }
  1904.   if (copy_of_chunky != NULL) {
  1905.     if (copy_of_chunky != (UBYTE *)GfxBase->ChunkyToPlanarPtr)
  1906.       free (copy_of_chunky);
  1907.     copy_of_chunky = NULL;
  1908.   }
  1909.   if (tmp_bm != NULL) {
  1910.     if (v39)
  1911.       FreeBitMap (tmp_bm);
  1912.     else
  1913.       FreeMem (tmp_bm, sizeof(struct BitMap));
  1914.     tmp_bm = NULL;
  1915.   }
  1916.   if (tmpras != NULL) {
  1917.     FreeRaster (tmpras, screen_width, screen_depth);
  1918.     tmpras = NULL;
  1919.   }
  1920. }
  1921.  
  1922. /****************************************************************************/
  1923.  
  1924. void filerequestloop (struct options *opt)
  1925. {
  1926.   static char resultstring[128];
  1927.  
  1928.   if (AslBase != NULL) {
  1929.     while (AslRequest (fr, NULL)) {
  1930.       strcpy (resultstring, fr->rf_Dir);
  1931.       AddPart (resultstring, fr->rf_File, 128);
  1932.       animate_file (resultstring, *opt);
  1933.     }
  1934.   }
  1935. }
  1936.  
  1937. /****************************************************************************/
  1938.  
  1939. LONG argarray[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  1940.  
  1941. int main (int argc, char *argv[])
  1942. {
  1943.   struct WBStartup *argmsg;
  1944.   struct WBArg *wb_arg;
  1945.   char **fnames;
  1946.   UWORD ktr;
  1947.   struct options opt;
  1948.  
  1949.  
  1950.   /* standard libraries are auto-opened here by SAS/C */
  1951.  
  1952.   /* find out about ourself */
  1953.   thistask = FindTask (NULL);
  1954.   GetProgramName (programname, 19);
  1955.   v39 = (GfxBase->LibNode.lib_Version >= 39);
  1956.   v40 = (GfxBase->LibNode.lib_Version >= 40);
  1957.   if ((SysBase->AttnFlags & AFF_68040) != 0)
  1958.     cpu_type = 68040;
  1959.   else if ((SysBase->AttnFlags & AFF_68030) != 0)
  1960.     cpu_type = 68030;
  1961.   else if ((SysBase->AttnFlags & AFF_68020) != 0)
  1962.     cpu_type = 68020;
  1963.   else if ((SysBase->AttnFlags & AFF_68010) != 0)
  1964.     cpu_type = 68010;
  1965.   else
  1966.     cpu_type = 68000;
  1967.  
  1968.   /* timer stuff */
  1969.   if ((timermp = CreatePort (0, 0)) == NULL)
  1970.     die ("%s: Can't create messageport!", programname);
  1971.   if ((timerio = (struct timerequest *)CreateExtIO (timermp,
  1972.                  sizeof(struct timerequest))) == NULL)
  1973.     die ("%s: Can't create External IO!", programname);
  1974.   if (timerclosed = OpenDevice (TIMERNAME, UNIT_MICROHZ,
  1975.                                 (struct IORequest *)timerio, 0))
  1976.     die ("%s: Can't open timer.device!", programname);
  1977.   TimerBase = (struct Library *)timerio->tr_node.io_Device;
  1978.   if ((time = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
  1979.                                           MEMF_CLEAR | MEMF_PUBLIC)) == NULL ||
  1980.       (time0 = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
  1981.                                           MEMF_CLEAR | MEMF_PUBLIC)) == NULL ||
  1982.       (time1 = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
  1983.                                           MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
  1984.     die ("%s: Out of memory", programname);
  1985.   micros_per_eclock = 1000000.0 / (double)ReadEClock (time);
  1986.  
  1987.   /* set default switches */
  1988.   opt.ram = TRUE;
  1989.   opt.mode = MODE_COLOUR;
  1990.   opt.once = FALSE;
  1991.   opt.rom = FALSE;
  1992.   opt.dbuf = FALSE;
  1993.   opt.warp = FALSE;
  1994.   opt.akiko = TRUE;
  1995.  
  1996.   /* Allocate filerequester and screenmode requester */
  1997.   if ((AslBase = OpenLibrary ("asl.library", 37L)) != NULL) {
  1998.     if ((fr = (struct FileRequester *)AllocAslRequestTags (ASL_FileRequest,
  1999.              ASL_Hail,           (ULONG)programname,
  2000.              ASL_Pattern,        AslBase->lib_Version < 39 ? (ULONG)"#?.fl?"
  2001.                                                            : (ULONG)"#?.fl[ic]",
  2002.              ASL_OKText,         (ULONG)"Play",
  2003.              ASL_CancelText,     (ULONG)"Cancel",
  2004.              ASL_FuncFlags,      FILF_PATGAD,
  2005.              TAG_DONE)) == NULL)
  2006.       die ("%s: Can't allocate file requester\n", programname);
  2007.     if (AslBase->lib_Version >= 38)
  2008.       if ((smr = AllocAslRequestTags (ASL_ScreenModeRequest,
  2009.              ASLSM_MaxDepth,     8,
  2010.              ASLSM_PropertyMask, DIPF_IS_EXTRAHALFBRITE | DIPF_IS_DUALPF |
  2011.                                  DIPF_IS_PF2PRI | DIPF_IS_HAM,
  2012.              TAG_DONE)) == NULL)
  2013.         die ("%s: Can't allocate screenmode requester\n", programname);
  2014.   }
  2015.  
  2016.   /* try opening EGS libraries */
  2017.   if ((EGSBase = OpenLibrary ("egs.library", 0)) != NULL &&
  2018.       (EGSGfxBase = OpenLibrary ("egsgfx.library", 0)) != NULL &&
  2019.       (EGSBlitBase = OpenLibrary ("egsblit.library", 0)) != NULL &&
  2020.       (EGSIntuiBase = OpenLibrary ("egsintui.library", 0)) != NULL) {
  2021.     opt.mode = MODE_EGS;
  2022.   }
  2023.  
  2024.   /* parse workbench message or commandline */
  2025.   if (argc == 0) {
  2026.     argmsg = (struct WBStartup *)argv;
  2027.     wb_arg = argmsg->sm_ArgList;
  2028.     strcpy (programname, wb_arg->wa_Name);
  2029.     parse_tooltypes (wb_arg->wa_Name, &opt);
  2030.     if (argmsg->sm_NumArgs <= 1)
  2031.       filerequestloop (&opt);
  2032.     else {
  2033.       wb_arg++;
  2034.       for (ktr = 1; ktr < argmsg->sm_NumArgs; ktr++, wb_arg++)
  2035.         if (wb_arg->wa_Lock != NULL) {
  2036.           olddir = CurrentDir (wb_arg->wa_Lock);
  2037.           animate_file (wb_arg->wa_Name, opt);
  2038.           CurrentDir (olddir);
  2039.           olddir = NULL;
  2040.         } else
  2041.           animate_file (wb_arg->wa_Name, opt);
  2042.       }
  2043.   } else {
  2044.     if ((rdargs = ReadArgs
  2045.         ("FILE/M,DISK/S,RAM/S,ONCE/S,COLOUR/S,COLOR/S,EHB/S,COLOUR4/S,COLOR4/S,GREY/S,GRAY/S,EGS/S,ROM/S,DBUF/S,WARP/S,NOAKIKO/S",
  2046.                             argarray, NULL)) != NULL) {
  2047.       if (argarray[1])
  2048.         opt.ram = FALSE;
  2049.       if (argarray[2])
  2050.         opt.ram = TRUE;
  2051.       if (argarray[3])
  2052.         opt.once = TRUE;
  2053.       if (argarray[4] || argarray[5])
  2054.         opt.mode = MODE_COLOUR;
  2055.       if (argarray[6])
  2056.         opt.mode = MODE_EHB;
  2057.       if (argarray[7] || argarray[8])
  2058.         opt.mode = MODE_COLOUR4;
  2059.       if (argarray[9] || argarray[10])
  2060.         opt.mode = MODE_GREY;
  2061.       if (argarray[11])
  2062.         opt.mode = MODE_EGS;
  2063.       if (argarray[12])
  2064.         opt.rom = TRUE;
  2065.       if (argarray[13])
  2066.         opt.dbuf = TRUE;
  2067.       if (argarray[14])
  2068.         opt.warp = TRUE;
  2069.       if (argarray[15])
  2070.         opt.akiko = FALSE;
  2071.       fnames = (char **)argarray[0];
  2072.       if (fnames == NULL || *fnames == NULL)
  2073.         filerequestloop (&opt);
  2074.       else
  2075.         while (*fnames != NULL)
  2076.           animate_file (*fnames++, opt);
  2077.       FreeArgs (rdargs);
  2078.       rdargs = NULL;
  2079.     }
  2080.   }
  2081.  
  2082.   /* Let the user see how fast it went before the window closes */
  2083.   if (argc == 0)
  2084.     Delay (200);
  2085.  
  2086.   /* exit program with success code */
  2087.   return (0);
  2088.  
  2089.   /* SAS/C executes _STDcleanup() automatically on exit or break */
  2090.  
  2091. }
  2092.  
  2093. /****************************************************************************/
  2094.